/** @file         task_control_main.c
 *  @brief        简要说明
 *  @details      详细说明
 *  @author       lzm
 *  @date         2022-03-16 20:49:46
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/

#include <stdio.h>
#include <stdlib.h>

#include "FreeRTOS.h"
#include "task.h"

/*
**********************************************************************************************************
											函数声明
**********************************************************************************************************
*/
static void appTaskCreate (void* parameter); // 初始任务，主要用于创建任务
static void lzmStaticTestTask (void* parameter); // 创建静态内存任务
static void lzmTestTask (void* parameter); // 创建动态内存任务


/*
**********************************************************************************************************
											句柄变量声明
**********************************************************************************************************
*/
static TaskHandle_t appTaskCreateHandle = NULL;
static TaskHandle_t lzmStaticTestTaskHandle = NULL;
static TaskHandle_t lzmTestTaskHandle = NULL;

/*
**********************************************************************************************************
											全局变量声明
**********************************************************************************************************
*/
/* 静态内存任务 */
/* 任务控制快 */
static StaticTask_t lzmStaticTestTaskTCB = {0};
/* 任务堆栈 */
static StackType_t lzmStaticTestTaskStack[256] = {0};

/*
**********************************************************************************************************
											静态内存任务相关
**********************************************************************************************************
*/
/**
* 使用了静态分配内存，以下这两个函数是由用户实现，函数在 task.c 文件中有引用
* 当且仅当 configSUPPORT_STATIC_ALLOCATION 这个宏定义为 1 的时候才有效
*/
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
                                    StackType_t **ppxTimerTaskStackBuffer,
                                    uint32_t *pulTimerTaskStackSize);

void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
                                   StackType_t **ppxIdleTaskStackBuffer,
                                   uint32_t *pulIdleTaskStackSize);    

/* 空闲任务任务堆栈 */
static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE];
/* 定时器任务堆栈 */
static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH];

/* 空闲任务控制块 */
static StaticTask_t Idle_Task_TCB;
/* 定时器任务控制块 */
static StaticTask_t Timer_Task_TCB;

/********************************** 内核对象句柄 *********************************/
/*
 * 信号量，消息队列，事件标志组，软件定时器这些都属于内核的对象，要想使用这些内核
 * 对象，必须先创建，创建成功之后会返回一个相应的句柄。实际上就是一个指针，后续我
 * 们就可以通过这个句柄操作这些内核对象。
 *
 * 内核对象说白了就是一种全局的数据结构，通过这些数据结构我们可以实现任务间的通信，
 * 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
 * 来完成的
 * 
 */

/** @brief main 
  * @details main
  * @param 
  * @retval 
  * @author lizhuming
  */
int main()
{
    BaseType_t xReturn = pdPASS;

    /* 硬件初始化 */
    printf("start...\r\n");

    /* 创建初始任务 */
    xReturn = xTaskCreate((TaskFunction_t) appTaskCreate, // 任务入口函数
                          (const char*) "appTaskCreate", // 任务函数名
                          (uint16_t   )256, // 任务堆栈大小
                          (void*      )NULL, // 传递给任务入口函数的参数
                          (UBaseType_t)10, // 任务优先及
                          (TaskHandle_t* )&appTaskCreateHandle); // 任务控制快地址

    /* 启动调度，开始执行任务 */
    if(xReturn == pdPASS)
    {
        printf("tast create success\r\n");
        
        vTaskStartScheduler();
    }

    while(1)
    {
        /* error：能跑到这里，说明系统有问题 */
        printf("RTOS ERROR!!!\r\n");
    }

    return 1;
}

/** @brief appTaskCreate
  * @details 
  * @param 
  * @retval 
  * @author lizhuming
  */
static void appTaskCreate (void* parameter)
{
    BaseType_t xReturn = pdPASS;

    printf("RTOS START...\r\n");

    taskENTER_CRITICAL(); // 进入临界

    /* 创建静态内存任务 */
    lzmStaticTestTaskHandle = xTaskCreateStatic((TaskFunction_t) lzmStaticTestTask, // 任务入口函数
                                                (const char*) "lzm static test task", // 任务函数名
                                                (uint32_t   )256, // 任务堆栈大小
                                                (void*      )NULL, // 传递给任务入口函数的参数
                                                (UBaseType_t)5, // 任务优先及
                                                (StackType_t*  )lzmStaticTestTaskStack, // 任务堆栈地址
                                                (StaticTask_t* )&lzmStaticTestTaskTCB); // 任务控制块地址

    /* 创建动态内存任务 */
    xReturn = xTaskCreate((TaskFunction_t) lzmTestTask, // 任务入口函数
                          (const char*) "lzm test task", // 任务函数名
                          (uint16_t   )256, // 任务堆栈大小
                          (void*      )NULL, // 传递给任务入口函数的参数
                          (UBaseType_t)5, // 任务优先及
                          (TaskHandle_t* )&lzmTestTaskHandle); // 任务句柄

    if(xReturn == pdPASS)
    {
        printf("creat lzm test task success!!!");
    }

    vTaskDelete(appTaskCreateHandle); // 删除初始任务
    
    taskEXIT_CRITICAL(); // 退出临界
}

/** @brief lzmStaticTestTack
  * @details 
  * @param 
  * @retval 
  * @author lizhuming
  */
static void lzmStaticTestTask(void* parameter)
{
    int run_cnt = 0;

	/* task init */
    printf("start lzmStaticTestTask\r\n");

    for(;;)
    {
        // printf("this is a lzm static test task for run [%d]\r\n", run_cnt);

        run_cnt++;
        if(run_cnt > 1000)
        {
            run_cnt = 0;
        }

        vTaskDelay(2000);
    }
}

/** @brief lzmTestTask
  * @details 
  * @param 
  * @retval 
  * @author lizhuming
  */
static void lzmTestTask(void* parameter)
{
    int run_cnt = 0;
    int tick_cnt = 0;
	/* task init */
    printf("start lzmTestTask\r\n");

    for(;;)
    {
        // printf("this is a lzm test task for run [%d]\r\n", run_cnt);

        run_cnt++;
        if(run_cnt > 10)
        {
            run_cnt = 0;
        }

        tick_cnt = xTaskGetTickCount();

        printf("tick count is [%d]\r\n", tick_cnt);
        
        vTaskDelay(500);
    }
}

/** @brief vApplicationGetIdleTaskMemory
  * @details 获取空闲任务的任务堆栈和任务控制块内存
  * @param 
  * @retval 
  * @author lizhuming
  */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
                                   StackType_t **ppxIdleTaskStackBuffer,
                                   uint32_t *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer=&Idle_Task_TCB;/* 任务控制块内存 */
    *ppxIdleTaskStackBuffer=Idle_Task_Stack;/* 任务堆栈内存 */
    *pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;/* 任务堆栈大小 */
}

/** @brief vApplicationGetTimerTaskMemory
  * @details 获取定时器任务的任务堆栈和任务控制块内存
  * @param 
  * @retval 
  * @author lizhuming
  */
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
                                    StackType_t **ppxTimerTaskStackBuffer,
                                    uint32_t *pulTimerTaskStackSize)
{
    *ppxTimerTaskTCBBuffer=&Timer_Task_TCB;/* 任务控制块内存 */
    *ppxTimerTaskStackBuffer=Timer_Task_Stack;/* 任务堆栈内存 */
    *pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;/* 任务堆栈大小 */
}

